// Package utils 提供了通用的工具函数。
// 该文件包含密码哈希、JWT 生成与解析等功能。
package utils

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt"
	"golang.org/x/crypto/bcrypt"
)

// HashPassword 使用 bcrypt 对密码进行哈希处理。
// 参数：
//   - pwd: 明文密码。
//
// 返回值：
//   - string: 哈希后的密码。
//   - error: 处理过程中可能出现的错误。
func HashPassword(pwd string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(pwd), 12) // 使用 bcrypt 生成哈希，成本因子为 12。
	return string(hash), err
}

// GenerateJWT 生成一个包含用户名的 JWT 令牌。
// 参数：
//   - username: 用户名。
//
// 返回值：
//   - string: 生成的 JWT 令牌（带 "Bearer " 前缀）。
//   - error: 生成过程中可能出现的错误。
func GenerateJWT(username string) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"username": username,                              // 将用户名存储在声明中。
		"exp":      time.Now().Add(time.Hour * 72).Unix(), // 设置令牌过期时间为 72 小时后。
	})

	signedToken, err := token.SignedString([]byte("secret")) // 使用 "secret" 作为签名密钥。
	return "Bearer " + signedToken, err
}

// CheckPassword 比较明文密码和哈希密码是否匹配。
// 参数：
//   - password: 明文密码。
//   - hash: 哈希密码。
//
// 返回值：
//   - bool: 是否匹配。
func CheckPassword(password string, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) // 使用 bcrypt 验证密码。
	return err == nil
}

// ParseJWT 解析 JWT 令牌并返回其中的用户名。
// 参数：
//   - tokenString: 包含 "Bearer " 前缀的 JWT 字符串（如 "Bearer xxxx.yyyy.zzzz"）。
//
// 返回值：
//   - string: 解析出的用户名。
//   - error: 解析过程中的任何错误。
func ParseJWT(tokenString string) (string, error) {
	// 1. 去除 "Bearer " 前缀（如果存在）。
	if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
		tokenString = tokenString[7:]
	}

	// 2. 解析 JWT 令牌。
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 2.1 验证签名算法是否是 HMAC。
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected Signing Method")
		}
		// 2.2 返回用于验证签名的密钥（这里使用硬编码的 "secret"）。
		return []byte("secret"), nil
	})

	// 3. 检查解析错误。
	if err != nil {
		return "", err
	}

	// 4. 提取声明 (claims) 并验证令牌有效性。
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		// 4.1 从 claims 中获取 username 字段。
		username, ok := claims["username"].(string)
		if !ok {
			return "", errors.New("username claim is not a string")
		}
		// 4.2 返回用户名。
		return username, nil
	}

	// 5. 如果以上条件都不满足，返回错误。
	return "", err
}
